package com.whfc.mach.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.whfc.common.enums.DeviceType;
import com.whfc.common.enums.FenceType;
import com.whfc.common.exception.BizException;
import com.whfc.common.obd.ObdFrame;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.third.map.MapApi;
import com.whfc.common.third.map.MapLoc;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.MathUtil;
import com.whfc.common.util.PositionUtil;
import com.whfc.influx.dao.AppDeviceObdLogDao;
import com.whfc.mach.dao.AppMachDataMapper;
import com.whfc.mach.dao.AppMachDayMapper;
import com.whfc.mach.dao.AppMachDeviceMapper;
import com.whfc.mach.dao.AppMachMapper;
import com.whfc.mach.dto.AppMachDTO;
import com.whfc.mach.dto.AppMachDayDTO;
import com.whfc.mach.dto.AppMachInfo;
import com.whfc.mach.dto.Gps;
import com.whfc.mach.dto.obd.*;
import com.whfc.mach.entity.AppDeviceObdLog;
import com.whfc.mach.entity.AppMach;
import com.whfc.mach.entity.AppMachData;
import com.whfc.mach.enums.NetState;
import com.whfc.mach.manager.MachConfigManager;
import com.whfc.mach.manager.ObdDataMgr;
import com.whfc.mach.service.ObdDataService;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2020/9/25 18:15
 */
@DubboService(interfaceClass = ObdDataService.class, version = "1.0.0")
public class ObdDataServiceImpl implements ObdDataService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AppMachMapper appMachMapper;

    @Autowired
    private AppMachDataMapper appMachDataMapper;

    @Autowired
    private AppDeviceObdLogDao appDeviceObdLogDao;

    @Autowired
    private ObdDataMgr obdDataMgr;

    @Autowired
    private MachConfigManager machConfigManager;

    @Autowired
    private AppMachDeviceMapper appMachDeviceMapper;

    @Autowired
    private AppMachDayMapper machDayMapper;

    @Autowired
    private MapApi mapApi;


    @Override
    public ObdDataDTO getObdData(Integer machId) throws BizException {
        logger.info("获取设备obd信息服务,machId:{}", machId);
        AppMach appMach = appMachMapper.selectByPrimaryKey(machId);
        if (appMach == null) {
            throw new BizException(ResultEnum.NOT_FOUND.getCode(), "未找到该设备信息");
        }
        ObdDataDTO data = new ObdDataDTO();
        // 查找设备实时状态
        AppMachData appMachData = appMachDataMapper.selectByMachId(machId);
        if (appMachData != null) {
            data.setNetState(appMachData.getNetState());
            data.setWorkState(appMachData.getWorkState());
            data.setTotalWorkHours(appMachData.getTotalWorkHours());
            Long totalLength1 = appMachData.getTotalLength1() == null ? 0 : appMachData.getTotalLength1();
            Long totalLength2 = appMachData.getTotalLength2() == null ? 0 : appMachData.getTotalLength2();
            data.setMile(totalLength1 + totalLength2);
            data.setOilWear(appMachData.getTotalOilWear());
            Double lat = appMachData.getLat();
            Double lng = appMachData.getLng();
            if (lat != null && lng != null) {
                MapLoc loc = mapApi.geocode(lng, lat);
                data.setLat(appMachData.getLat());
                data.setLng(appMachData.getLng());
                data.setLocation(loc.getAddress());
            }
        }
        data.setDeviceId(appMach.getDeviceId());
        data.setSn(appMach.getSn());
        return data;
    }

    @Override
    public List<Gps> gpsLog(Integer machId, Date date) {
        logger.info("查找设备的运动轨迹服务,machId:{},date:{}", machId, date);

        AppMachDTO machDTO = appMachMapper.selectMachDTOById(machId);
        if (machDTO == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "设备不存在!");
        }
        String polygonWKT = machConfigManager.getPolygonWKT(machDTO.getDeptId(), machDTO.getMachTypeName());
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        List<AppDeviceObdLogDTO> obdLogDTOList = appDeviceObdLogDao.selectObdLogByMachId(machId, startTime, endTime);
        List<Gps> gpsLogList = new ArrayList<>();
        for (AppDeviceObdLogDTO logDTO : obdLogDTOList) {
            if (PositionUtil.contains(FenceType.POLYGON.value(), polygonWKT, null, logDTO.getLat(), logDTO.getLng())) {
                gpsLogList.add(toGps(logDTO));
            }
        }
        return gpsLogList;
    }

    @Override
    public ObdParamDTO getParamList(Integer machId) {
        logger.info("获取obd参数列表服务,machId:{}", machId);
        AppMachDTO machDTO = appMachMapper.selectMachDTOById(machId);
        if (machDTO == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "设备不存在!");
        }
        List<ObdFrame> list = obdDataMgr.getObdData(machDTO.getDeviceId());
        Integer workState = NetState.OFFLINE.getValue().equals(machDTO.getNetState()) ? NetState.OFFLINE.getValue() : machDTO.getWorkState();

        ObdParamDTO data = new ObdParamDTO();
        data.setFrameList(list);
        data.setTime(new Date());
        data.setDeviceTime(machDTO.getTime());
        data.setWorkState(workState);
        data.setBatteryPower(machDTO.getBatteryPower());
        data.setMachId(machId);
        data.setMachType(machDTO.getMachType());
        return data;
    }

    @Override
    public ObdParamDTO getParam(Integer machId) throws BizException {
        logger.info("获取obd参数列表服务,machId:{}", machId);
        AppMachDTO machDTO = appMachMapper.selectMachDTOById(machId);
        if (machDTO == null) {
            throw new BizException(ResultEnum.PARAM_ERROR.getCode(), "设备不存在!");
        }
        ObdParamDTO data = obdDataMgr.getObdParamData(machDTO.getDeviceId());
        Integer workState = NetState.OFFLINE.getValue().equals(machDTO.getNetState()) ? NetState.OFFLINE.getValue() : machDTO.getWorkState();
        data.setTime(new Date());
        data.setDeviceTime(machDTO.getTime());
        data.setWorkState(workState);
        data.setNetState(machDTO.getNetState());
        data.setBatteryPower(machDTO.getBatteryPower());
        data.setMachId(machId);
        data.setMachType(machDTO.getMachType());
        return data;
    }


    @Override
    public ObdOilDataDTO oilData(Integer machId, Date startDate, Date endDate) {
        logger.info("获取obd设备油耗数据(多天)服务,machId:{},startDate:{},endDate:{}", machId, startDate, endDate);
        // 查询每一天油耗
        List<AppMachDayDTO> list = obdDataMgr.getMachDayDataList(machId, startDate, endDate);
        int size = list.size();
        List<ObdDataDTO> oilWearList = new ArrayList<>(size);
        double totalOilWear = 0.0;
        for (AppMachDayDTO appMachDayDTO : list) {
            Double oilWear = appMachDayDTO.getOilWear();
            totalOilWear += oilWear;
            ObdDataDTO obdOilWearDTO = new ObdDataDTO();
            obdOilWearDTO.setOilWear(oilWear);
            obdOilWearDTO.setDate(appMachDayDTO.getDate());
            oilWearList.add(obdOilWearDTO);
        }

        ObdOilDataDTO result = new ObdOilDataDTO();
        result.setAvgOilWear(MathUtil.round(totalOilWear / size, 2));
        result.setTotalOilWear(MathUtil.round(totalOilWear, 2));
        result.setOilWearList(oilWearList);
        return result;
    }

    @Override
    public ObdOilDataDTO oilData(Integer machId, Date date) throws BizException {
        logger.info("获取obd设备油耗数据(一天)服务,machId:{},date:{}", machId, date);
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        List<ObdDataDTO> list = appDeviceObdLogDao.selectObdOilLogByMachId(machId, startTime, endTime);

        // 查找当天油耗
        AppMachDayDTO appMachDayDTO = machDayMapper.selectByMachIdAndDate(machId, date);
        Double totalOilWear = appMachDayDTO == null ? 0D : appMachDayDTO.getOilWear();
        ObdOilDataDTO data = new ObdOilDataDTO();
        data.setTotalOilWear(totalOilWear);
        data.setAvgOilWear(totalOilWear);
        data.setOilWearList(list);
        return data;
    }

    @Override
    public ObdMileDataDTO mileData(Integer machId, Date startDate, Date endDate) {
        logger.info("获取obd设备放线里程数据(多天)服务,machId:{},startDate:{},endDate:{}", machId, startDate, endDate);

        // 查询每一天放线里程
        List<AppMachDayDTO> list = obdDataMgr.getMachDayDataList(machId, startDate, endDate);
        int size = list.size();
        List<ObdDataDTO> dayMileList = new ArrayList<>(size);
        long totalMile = 0;
        long totalMile1 = 0;
        long totalMile2 = 0;
        for (AppMachDayDTO appMachDayDTO : list) {
            Long mileage = appMachDayDTO.getMileage();
            Long mileage1 = appMachDayDTO.getMileage1();
            Long mileage2 = appMachDayDTO.getMileage2();
            totalMile += mileage;
            totalMile1 += mileage1;
            totalMile2 += mileage2;
            ObdDataDTO obdDataDTO = new ObdDataDTO();
            obdDataDTO.setMile(mileage);
            obdDataDTO.setMile1(mileage1);
            obdDataDTO.setMile2(mileage2);
            obdDataDTO.setDate(appMachDayDTO.getDate());
            dayMileList.add(obdDataDTO);
        }

        ObdMileDataDTO result = new ObdMileDataDTO();
        // 总里程
        result.setMileEffic(MathUtil.round(1.0 * totalMile / size, 2));
        result.setTotalMile(totalMile);
        // 1轮里程
        result.setMileEffic1(MathUtil.round(1.0 * totalMile1 / size, 2));
        result.setTotalMile1(totalMile1);
        // 2轮里程
        result.setMileEffic2(MathUtil.round(1.0 * totalMile2 / size, 2));
        result.setTotalMile2(totalMile2);
        result.setMileList(dayMileList);
        return result;
    }

    @Override
    public ObdMileDataDTO mileData(Integer machId, Date date) throws BizException {
        logger.info("获取obd设备放线里程数据(单天)服务,machId:{},date:{}", machId, date);
        Date startTime = DateUtil.getDateBegin(date);
        Date endTime = DateUtil.getDateEnd(date);
        List<ObdDataDTO> list = appDeviceObdLogDao.selectObdMileLogByMachId(machId, startTime, endTime);
        // 处理数据
        this.handleMileData(list);

        // 查询当天的里程
        AppMachDayDTO appMachDayDTO = machDayMapper.selectByMachIdAndDate(machId, date);
        Double times = 0D;
        Long mileage = 0L;
        Long mileage1 = 0L;
        Long mileage2 = 0L;
        if (appMachDayDTO != null) {
            times = appMachDayDTO.getTimes();
            mileage = appMachDayDTO.getMileage();
            mileage1 = appMachDayDTO.getMileage1();
            mileage2 = appMachDayDTO.getMileage2();
        }
        ObdMileDataDTO data = new ObdMileDataDTO();
        data.setTotalMile(mileage);
        data.setMileEffic(times == 0 ? 0D : MathUtil.round(1.0 * mileage / times, 2));
        data.setTotalMile1(mileage1);
        data.setMileEffic1(times == 0 ? 0D : MathUtil.round(1.0 * mileage1 / times, 2));
        data.setTotalMile2(mileage2);
        data.setMileEffic2(times == 0 ? 0D : MathUtil.round(1.0 * mileage2 / times, 2));
        data.setMileList(list);
        return data;
    }

    @Override
    public PageData<AppDeviceObdLogDTO> getDeviceObdDataList(Integer deviceId, Date startTime, Date endTime, Integer pageNum, Integer pageSize) {
        String[] columns = new String[]{"deviceId", "time", "status", "lng", "lat", "location", "batteryPower", "masterVer"};
        return appDeviceObdLogDao.selectObdLogByDeviceId(deviceId, startTime, endTime, pageNum, pageSize, columns);
    }

    @Override
    public AppDeviceObdDataDTO getDeviceObdDataDetail(Integer deviceId, Date time) {
        return obdDataMgr.getObdData(deviceId, time);
    }

    @Override
    public void innerAddObdData(AppDeviceObdLog appDeviceObdLog) throws BizException {
        appDeviceObdLogDao.insert(appDeviceObdLog);
    }

    @Override
    public void statMachDayData(Date date) {
        logger.info("统计每天obd设备数据服务,date:{}", date);
        int pageNum = 1;
        int pageSize = 20;
        int pages;
        do {
            PageHelper.startPage(pageNum, pageSize);
            List<AppMachInfo> machInfoList = appMachDeviceMapper.selectAppMachInfoList(DeviceType.obd.getValue());
            PageInfo<AppMachInfo> pageInfo = PageInfo.of(machInfoList);
            logger.info("task-statObdDayData,total:{},pages:{},pageNum:{},pageSize:{}", pageInfo.getTotal(), pageInfo.getPages(), pageNum, pageSize);
            pages = pageInfo.getPages();
            pageNum++;
            for (AppMachInfo machInfo : machInfoList) {
                // 更新油耗和总放线里程
                obdDataMgr.statMachDayData(machInfo, date);
                // 更新工时和工时分段
                obdDataMgr.updateMachDaySegment(machInfo, date);
            }
        } while (pageNum <= pages);
    }

    @Override
    public void amendObdDeviceData(AppDeviceObdLog data) throws BizException {
        logger.info("修正obd硬件数据服务,param:{}", data.toString());
        obdDataMgr.amendObdDeviceData(data);
    }

    @Override
    public List<AppDeviceObdLogDTO> qzData(Integer machId, Date startTime, Date endTime) throws BizException {
        logger.info("获取一段时间的牵张数据服务,machId:{},startTime:{},endTime:{}", machId, startTime, endTime);
        List<AppDeviceObdLogDTO> list = appDeviceObdLogDao.selectObdLogByMachId(machId, startTime, endTime);
        return list;
    }

    /**
     * 提取位置信息
     *
     * @param dataLog
     * @return
     */
    private Gps toGps(AppDeviceObdLogDTO dataLog) {
        Gps gps = new Gps();
        gps.setTime(dataLog.getTime());
        gps.setLng(dataLog.getLng());
        gps.setLat(dataLog.getLat());
        gps.setLocation(dataLog.getLocation());
        return gps;
    }

    /**
     * 处理里程数据
     *
     * @param list
     */
    private void handleMileData(List<ObdDataDTO> list) {
        for (int i = 0; i <= list.size() - 1; i++) {
            ObdDataDTO curDTO = list.get(i);
            Long totalLength1 = curDTO.getMile1();
            Long totalLength2 = curDTO.getMile2();

            // 第一个数据
            if (i == 0) {
                if (totalLength1 == null) {
                    totalLength1 = 0L;
                    curDTO.setMile1(totalLength1);
                }
                if (totalLength2 == null) {
                    totalLength2 = 0L;
                    curDTO.setMile2(totalLength2);
                }
                curDTO.setMile(totalLength1 + totalLength2);
                continue;
            }

            // 第二个数据开始
            if (totalLength1 == null) {
                ObdDataDTO preDTO = list.get(i - 1);
                totalLength1 = preDTO.getMile1();
                curDTO.setMile1(totalLength1);
            }
            if (totalLength2 == null) {
                ObdDataDTO preDTO = list.get(i - 1);
                totalLength2 = preDTO.getMile2();
                curDTO.setMile2(totalLength2);
            }
            curDTO.setMile(totalLength1 + totalLength2);
        }
    }
}
